﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.ServiceModel;
using AdventureWorks.Entities;
using AdventureWorks.Services.Enumerations;
using Xomega.Framework;
using Xomega.Framework.Services;

namespace AdventureWorks.Services
{
    public class EmployeeService : EntityServiceBase<AdvWorksEntities>, IEmployeeService
    {
        public EmployeeService()
        {
            ErrorList.ResourceManager = Resources.ResourceManager;
        }

        public List<Employee_ReadListOutput> ReadList(Employee_ReadListInput input)
        {
            //ErrorList.Current.AddError("TST1", "This is a first test message.");
            //ErrorList.Current.CriticalError("TST2", "This is a critical test message.");

            var employeeView = from employee in objCtx.Employee
                let address = employee.AddressObjectList.FirstOrDefault().AddressObject
                let contact = employee.ContactObject
                let manager = employee.ManagerObject.ContactObject
                select new Employee_ReadListOutput()
                {
                    Id = employee.EmployeeId,
                    FirstName = contact.FirstName,
                    LastName = contact.LastName,
                    Title = employee.Title,
                    Gender = employee.Gender,
                    HireDate = employee.HireDate,
                    Manager = manager.LastName,
                    Salaried = employee.SalariedFlag,
                    Current = employee.CurrentFlag,
                    StateId = address.StateProvinceIdObject.StateProvinceId,
                    Address = new Address()
                    {
                        StreetAddress = address.AddressLine1,
                        City = address.City,
                        State = address.StateProvinceIdObject.StateProvinceCode,
                        Zipcode = address.PostalCode,
                        Country = address.StateProvinceIdObject.CountryRegionCodeObject.CountryRegionCode
                    }
                };

            if (input.StateOperator != null)
            {
                switch (input.StateOperator)
                {
                    case Operators.IsOneOf:
                        employeeView = employeeView.WhereIn(t => t.StateId, input.State.Cast<int?>()); break;
                    default: ErrorList.Current.AddError("Invalid operator {0} for the State.", input.StateOperator); break;
                }
            }

            if (input.FirstNameOperator != null)
            {
                switch (input.FirstNameOperator)
                {
                    case Operators.Contains:
                        employeeView = employeeView.Where(e => e.FirstName.Contains(input.FirstName)); break;
                    case Operators.DoesNotContain:
                        employeeView = employeeView.Where(e => !e.FirstName.Contains(input.FirstName)); break;
                    case Operators.IsNull:
                        employeeView = employeeView.Where(e => e.FirstName == null); break;
                    case Operators.IsNotNull:
                        employeeView = employeeView.Where(e => e.FirstName != null); break;
                    default: ErrorList.Current.AddError("Invalid operator {0} for the First Name.", input.FirstNameOperator); break;
                }
            }

            if (input.HireDateOperator != null)
            {
                switch (input.HireDateOperator)
                {
                    case Operators.IsEqualTo:
                        employeeView = employeeView.Where(e => e.HireDate == input.HireDate); break;
                    case Operators.IsNotEqualTo:
                        employeeView = employeeView.Where(e => e.HireDate != input.HireDate); break;
                    case Operators.IsEarlierThan:
                        employeeView = employeeView.Where(e => e.HireDate < input.HireDate); break;
                    case Operators.IsLaterThan:
                        employeeView = employeeView.Where(e => e.HireDate > input.HireDate); break;
                    case Operators.IsBetween:
                        employeeView = employeeView.Where(e => e.HireDate >= input.HireDate && e.HireDate <= input.HireDate2); break;
                    case Operators.IsNull:
                        employeeView = employeeView.Where(e => e.HireDate == null); break;
                    case Operators.IsNotNull:
                        employeeView = employeeView.Where(e => e.HireDate != null); break;
                    default: ErrorList.Current.AddError("Invalid operator {0} for the Hire Date.", input.HireDateOperator); break;
                }
            }

            if (input.ZipcodeOperator != null)
            {
                switch (input.ZipcodeOperator)
                {
                    case Operators.IsOneOf:
                        employeeView = employeeView.WhereIn(e => e.Address.Zipcode, input.Zipcode); break;
                    case Operators.IsNoneOf:
                        employeeView = employeeView.WhereNotIn(e => e.Address.Zipcode, input.Zipcode); break;
                    case Operators.IsNull:
                        employeeView = employeeView.Where(e => e.Address.Zipcode == null); break;
                    case Operators.IsNotNull:
                        employeeView = employeeView.Where(e => e.Address.Zipcode != null); break;
                    default: ErrorList.Current.AddError("Invalid operator {0} for the Hire Date.", input.ZipcodeOperator); break;
                }
            }

            if (!string.IsNullOrEmpty(input.LastName))
                employeeView = employeeView.Where(e => e.LastName.Contains(input.LastName));

            if (!string.IsNullOrEmpty(input.ManagerLastName))
                employeeView = employeeView.Where(e => e.Manager.Contains(input.ManagerLastName));

            ErrorList.Current.AbortIfHasErrors();

            return employeeView.ToList();
        }

        public EmployeeKey Create()
        {
            Employee emp = new Employee();
            objCtx.AddToEmployee(emp);
            return new EmployeeKey() { EmployeeId = TempKeyId(emp.EntityKey) };
        }

        public Employee_ReadOutput Read(EmployeeKey input)
        {
            EntityKey key = GetEntityKey(typeof(Employee), input.EmployeeId);
            Employee emp = objCtx.GetObjectByKey(key) as Employee;
            Employee_ReadOutput res = new Employee_ReadOutput()
            {
                BirthDate = emp.BirthDate,
                CurrentFlag = emp.CurrentFlag,
                Gender = emp.Gender,
                HireDate = emp.HireDate,
                Login = emp.Login,
                MaritalStatus = emp.MaritalStatus,
                ModifiedDate = emp.ModifiedDate,
                NationalIDNumber = emp.NationalIDNumber,
                SalariedFlag = emp.SalariedFlag,
                SickLeaveHours = emp.SickLeaveHours,
                Title = emp.Title,
                VacationHours = emp.VacationHours
            };
            emp.ContactObjectReference.Load();
            res.Contact = new ContactInfo()
            {
                FirstName = emp.ContactObject.FirstName,
                LastName = emp.ContactObject.LastName,
                MiddleName = emp.ContactObject.MiddleName,
                Phone = emp.ContactObject.Phone,
                EmailAddress = emp.ContactObject.EmailAddress
            };
            emp.ManagerObjectReference.Load();
            res.Manager = emp.ManagerObject.EmployeeId;
            emp.PayHistoryObjectList.Load();
            var payHist = from ph in emp.PayHistoryObjectList
                          select new Employee_ReadOutput_PayHistory()
                          {
                              RateChangeDate = ph.RateChangeDate,
                              PayFrequency = ph.PayFrequency,
                              Rate = ph.Rate
                          };
            res.PayHistory = payHist.ToList();
            return res;
        }

        public void Update(Employee_UpdateInput input)
        {
            EntityKey key = GetEntityKey(typeof(Employee), input.EmployeeId);
            Employee emp = objCtx.GetObjectByKey(key) as Employee;
            ServiceUtil.CopyProperties(input, emp);
            if (input.Manager.HasValue)
            {
                EntityKey mgrKey = GetEntityKey(typeof(Employee), input.Manager.Value);
                emp.ManagerObject = objCtx.GetObjectByKey(mgrKey) as Employee;
            }
            if (emp.EntityState != EntityState.Added) emp.ContactObjectReference.Load();
            Contact cont = emp.ContactObject;
            if (cont == null)
            {
                cont = new Contact();
                cont.PasswordHash = "hash";
                cont.PasswordSalt = "salt";
                emp.ContactObject = cont;
            }
            ServiceUtil.CopyProperties(input.Contact, cont);
            cont.ModifiedDate = DateTime.Now;
            emp.ModifiedDate = DateTime.Now;
            //if (emp.EntityState == EntityState.Added) emp.Rowguid = Guid.NewGuid();
        }

        public void Delete(EmployeeKey input)
        {
            EntityKey key = GetEntityKey(typeof(Employee), input.EmployeeId);
            Employee emp = objCtx.GetObjectByKey(key) as Employee;
            objCtx.DeleteObject(emp);
        }

        public List<State> GetStates()
        {
            var states = from employee in objCtx.Employee
                         let st = employee.AddressObjectList.FirstOrDefault().AddressObject.StateProvinceIdObject
                         where st != null
                         select new State()
                         {
                             StateProvinceId = st.StateProvinceId,
                             StateProvinceCode = st.StateProvinceCode,
                             Name = st.Name,
                             CountryRegionCode = st.CountryRegionCodeObject.CountryRegionCode
                         };
            return states.Distinct().ToList();
        }

        public List<EmployeePayHistory_ReadListOutput> PayHistory_ReadList(EmployeeKey input)
        {
            EntityKey key = GetEntityKey(typeof(Employee), input.EmployeeId);
            Employee emp = objCtx.GetObjectByKey(key) as Employee;
            emp.PayHistoryObjectList.Load();
            var payHist = from ph in emp.PayHistoryObjectList
                          select new EmployeePayHistory_ReadListOutput()
                          {
                              RateChangeDate = ph.RateChangeDate,
                              PayFrequency = ph.PayFrequency,
                              Rate = ph.Rate
                          };
            return payHist.ToList();
        }
    }
}
